package com.develop.data.loan.manager.change.amount;

import com.develop.data.loan.manager.change.amount.api.LoanInstallmentAmountBudget;
import com.develop.data.loan.model.LoanContract;
import com.develop.data.loan.model.LoanInstallment;
import com.develop.data.loan.option.LoanRateType;
import org.javamoney.moneta.Money;
import org.springframework.stereotype.Component;

import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.MonetaryRounding;
import javax.money.RoundingQueryBuilder;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Optional;

@Component("L0001B0001LoanInstallmentInterestOverdueBudget")
public class L0001B0001LoanInstallmentInterestOverdueBudget implements LoanInstallmentAmountBudget {

    /* 已发生形态转移 */
    /* 持有时间，左受制于动帐时间，右受制于转非应计时间（不计息） */
    /* LoanInstallmentInterestOverdue对应Installment的InterestOverdue金额字段 */

    public MonetaryAmount preview(LoanInstallment installment, LocalDateTime cursorDate){

        MonetaryAmount amount = Money.zero(Monetary.getCurrency("CNY"));
        LocalDateTime lastCursorDate = installment.getInstallmentCursor();
        LocalDateTime freezeDate = Optional.ofNullable(installment.getInstantFrozen()).orElse(LocalDateTime.MAX);

        LoanContract contract = installment.getLoanContract();
        LoanRateType rateType = contract.getLoanRateType();
        BigDecimal rateDaily = new BigDecimal(contract.getContractRateValue());

        LocalDateTime valueDate = contract.getContractValueDate();
        LocalDateTime headDate = installment.getInstallmentHead();
        LocalDateTime tailDate = installment.getInstallmentTail();
        
        LocalDateTime leftDate;
        LocalDateTime rightDate;
        
        /* 非历史期次 */
        leftDate = cursorDate;
        rightDate = tailDate;
        if (Duration.between(leftDate, rightDate).toDays() > 0) {
            return amount;
        }

        /* 历史期次，每期首尾左闭右开，每期天数算头不算尾 */

        /* 累计的 */
        amount = amount.add(installment.getInstallmentInterestOverdue());
        /* 已还的 */
        amount = amount.subtract(installment.getInstallmentInterestOverdueCleared());

        /* 新增的 */
        long days = 0;
        if(Duration.between(lastCursorDate, cursorDate).toDays() > 0){

            if(Duration.between(cursorDate, freezeDate).toDays() >= 0){
                leftDate = lastCursorDate;
                rightDate = cursorDate;
                days = Duration.between(leftDate, rightDate).toDays() + 1;
            }
            MonetaryRounding rounding = Monetary.getRounding(RoundingQueryBuilder.of().setScale(2).set(RoundingMode.FLOOR).build());

            MonetaryAmount principal = installment.getContractPrincipalAccrualOpening().subtract(
                    installment.getInstallmentPrincipalCleared()
            );

            amount = amount.add(
                    principal.multiply(days).multiply(rateDaily).with(rounding)
            );
        }


        leftDate = tailDate;
        rightDate = cursorDate.isBefore(freezeDate)? cursorDate: freezeDate;

        days = Duration.between(leftDate, rightDate).toDays() + 1;
        MonetaryAmount interest = installment.getInstallmentInterestOverdue();
        MonetaryAmount principal = installment.getInstallmentPrincipalOverdue();
        MonetaryRounding rounding = Monetary.getRounding(RoundingQueryBuilder.of().setScale(2).set(RoundingMode.FLOOR).build());
        amount = principal.multiply(days).multiply(rateDaily).with(rounding).add(interest);
        return amount;
        
    }

    public MonetaryAmount execute(LoanInstallment loanInstallment, LocalDateTime cursorDate, MonetaryAmount amount){

        /* 有借必有贷 */
        /* 还款金额任意，按金额依次扣除，直到扣完 */

        MonetaryAmount amountPreviewed = this.preview(loanInstallment, cursorDate);

        if(amount.isGreaterThanOrEqualTo(amountPreviewed)){
            loanInstallment.setInstallmentInterestOverdue(loanInstallment.getInstallmentInterestOverdue().subtract(amountPreviewed));
            loanInstallment.setInstallmentInterestCleared(loanInstallment.getInstallmentInterestCleared().add(amountPreviewed));
            loanInstallment.setInstallmentCursor(cursorDate);
            return amount.subtract(amountPreviewed);
        };

        loanInstallment.setInstallmentInterestOverdue(loanInstallment.getInstallmentInterestOverdue().subtract(amount));
        loanInstallment.setInstallmentInterestCleared(loanInstallment.getInstallmentInterestCleared().add(amount));
        loanInstallment.setInstallmentCursor(cursorDate);
        return Money.zero(Monetary.getCurrency("CNY"));

    }
}
